package threadTest.CASTest;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 功能描述: 自定义的自旋锁
 * 2024/03/13
 * <p>
 * ZhangYi
 */
public class MyCASLock {
    // 自选锁,  Interget 默认为0  如果是一个对象, 默认为 null
    /***
     * 自旋锁主要用于多线程编程中，特别是在那些对持有锁时间较短且上下文切换开销较大的并发场景下。以下是自旋锁适用的典型应用场景：
     * 短时间临界区： 当临界区（需要互斥访问的代码段）执行时间很短时，使用自旋锁可能更高效，因为等待锁的线程会持续尝试获取锁而不是被挂起和唤醒，这样可以避免昂贵的线程上下文切换。
     * 低优先级反转风险： 在某些场合下，如果高优先级线程因等待低优先级线程释放锁而阻塞，可能会导致优先级反转问题。自旋锁可以减少这种情况下不必要的上下文切换，降低优先级反转的风险。
     * 中断处理或内核态操作： 在操作系统内核或者硬件驱动程序等环境里，自旋锁经常被用于保护共享资源，尤其是在中断服务例程（ISR）中，由于不能睡眠（即不能进行线程调度），只能使用自旋锁来确保在中断处理过程中对共享数据的正确访问。
     * NUMA系统优化： 在非统一内存访问（NUMA）架构的系统中，CPU访问本地内存的速度远高于访问远程内存。当预期锁很快会被释放，并且锁所在的内存与当前试图获取锁的CPU核心紧密关联时，使用自旋锁能够减少远程内存访问带来的延迟。
     * 性能关键路径： 在性能敏感的应用中，尤其是对于实时性要求较高的系统，如果线程持有锁的时间极短且可预测，则自旋锁允许线程在不放弃CPU的情况下尽快重新尝试获取锁。
     * 然而，需要注意的是，自旋锁并不适用于所有情况，它的一个主要缺点是当锁长时间无法获取时，会导致占用CPU资源不断循环检测，这不仅浪费了处理器时间片，还可能导致其他任务饥饿。因此，在预计持有锁时间较长或者系统负载较高时，应考虑使用传统的互斥锁（Mutex）或其他同步机制。
     */
    private AtomicReference<Thread> holder = new AtomicReference<>();

    public void lock(){
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName());
        while (!holder.compareAndSet(null,
                                     thread)){
            // 自旋
        }
    }

    public void unlock(){
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName());
        Thread t = holder.getAndSet(null);
        if (t != null){
            System.out.println(thread.getName()+" unLock ");
        }
    }

    public void lockTimes(int times){
        String name = Thread.currentThread().getName();
        System.out.println(String.format("%s 尝试获取锁,如果执行 %d s内 无法获取将不进行获取",
                                         name,
                                         times));

        for (int i = 0; i < times; i++) {
            try {
                TimeUnit.SECONDS.sleep(1); // 1s 1次尝试获取锁
                if (holder.compareAndSet(null, Thread.currentThread())) {
                    return; // 获取锁成功
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

}
